package source

import (
	"reflect"

	"gitee.com/mkwchecking/sr-core/yerr"
	"github.com/go-kratos/kratos/v2/config"
	"github.com/go-kratos/kratos/v2/config/env"
	"github.com/go-kratos/kratos/v2/config/file"
)

type Observer = config.Observer

type ISource interface {
	Scan(obj interface{}) error
	Load() error
	Watch(key string, observer Observer) error
}

func New(opts ...Option) (*Source, error) {
	c := newDefault()
	for _, o := range opts {
		o(c)
	}

	srcs := make([]config.Source, 0)

	if c.Filepath != "" {
		srcs = append(srcs, file.NewSource(c.Filepath))
	}

	if c.EnvPrefix != "" {
		srcs = append(srcs, env.NewSource(c.EnvPrefix))
	}

	s := &Source{
		cfg: config.New(config.WithSource(srcs...)),
	}
	return s, s.Load()
}

type Source struct {
	cfg config.Config
}

func (s *Source) Load() error {
	return s.cfg.Load()
}

func (s *Source) Scan(v interface{}) error {
	if vt := reflect.TypeOf(v); vt.Kind() != reflect.Ptr {
		return yerr.ErrBizTypeInvalid.Errorf("source.Source Scan() only support pointer type")
	}

	return s.cfg.Scan(v)
}

func (s *Source) Watch(key string, observer Observer) error {
	return s.cfg.Watch(key, observer)
}
